/*
 * Copyright (C) 2007-2008  Hylke van der Schaaf
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, in version 3 of the License.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package hextd.UI;

import hextd.HexTD.GameState;
import hextd.core.gameloop.GameLoopImplementation.GliMpCatchup;
import hextd.message.MessageChannelList.ChannelInfo;
import hextd.network.NetworkClient;
import hextd.network.NetworkConnector;
import hextd.network.NetworkUser;
import hextd.core.ContextNormal;
import hextd.core.ContextNormal.AuthStatus;
import hextd.core.ContextPlayer;
import hextd.core.gameloop.GameLoopImplementation;
import hextd.message.Message;
import hextd.message.MessageChannelList;
import hextd.message.MessageChannelCreate;
import hextd.message.MessageFactory;
import hextd.message.MessagePlayerInChannel;
import hextd.message.MessageChannelJoin;
import hextd.message.MessageKickPlayer;
import hextd.message.MessagePing;
import hextd.message.MessagePlayerAuth;
import hextd.message.MessageError;
import hextd.message.MessageFetch;
import hextd.message.MessageFetch.FetchType;
import hextd.message.MessagePlayerForfeit;
import hextd.message.MessagePlayerInfo;
import hextd.message.MessagePlayerList;
import hextd.message.MessagePlayerList.MPPlayerInfo;
import hextd.message.MessageReplayBasic;
import hextd.message.MessageSay;
import hextd.message.MessageSettings;
import hextd.network.LineListener;
import hextd.network.NetworkConnection;
import hextd.server.PlayerInfo;
import hextd.util.HTMLEncode;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Timer;
import java.util.TimerTask;
import javax.swing.DefaultListModel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.border.TitledBorder;
import javax.swing.text.html.HTMLEditorKit;
import javax.swing.text.html.StyleSheet;

/**
 *
 * @author  hylke
 */
public class PanelNetConnection extends javax.swing.JPanel implements NetworkUser, NetworkConnector {

	private ContextNormal context;
	private StringBuilder htmlContent;
	private NetworkClient client;
	private String serverAddress;
	private int serverPort;
	//
	private Map<Integer, ChannelInfo> channelsById;
	private List<MPPlayerInfo> players = new ArrayList<MPPlayerInfo>();
	private Map<Integer, MPPlayerInfo> playersByUserId = new HashMap<Integer, MPPlayerInfo>();
	private Map<Integer, MPPlayerInfo> playersByGameId = new HashMap<Integer, MPPlayerInfo>();
	private Integer channelId;
	private String channelName;
	private final PlayerInfo localPlayerInfo = new PlayerInfo();
	private int playerGameId;
	private String status = "Not connected to server.";
	//
	private Timer pingTimer;
	private TimerTask pingTask;
	//
	private HTMLEditorKit editorkit;
	private PlayerListRenderer plr;
	//
	private String sendLater;
	private boolean keepTextBar = true;
	//
	private boolean wasConnected = false;
	private boolean keepFullLog = false;
	private StringBuilder fullLog = new StringBuilder();

	/** Creates new form PanelNetConnection */
	public PanelNetConnection() {
		channelsById = new HashMap<Integer, ChannelInfo>();
		editorkit = new HTMLEditorKit();
	}

	public void setContext(ContextNormal c) {
		context = c;
		doInit();
		c.setNetwork(this);

		StyleSheet s = context.loadStyleSheet("styles.css");
		editorkit.setStyleSheet(s);
		jTextPane_output.setEditorKit(editorkit);
	}

	private void doInit() {
		initComponents();
		plr = new PlayerListRenderer(context.colors);
		jListPlayerList.setCellRenderer(plr);
		jPanelInLobby.setVisible(false);
		jButtonExit.setVisible(false);
		setNoConnection();
		htmlContent = new StringBuilder();
	}

	public JPanel getChannelList() {
		return jPanelChannels;
	}

	/**
	 * Checks if the game has progressed enough that leaving means forfeiting.
	 * Presents the user with a question if this is the game.
	 * @return true if user really wants to leave
	 */
	public boolean optionalForfeitGame() {
		switch (context.getGameState()) {
			case mpPlaying:
			case mpCatchup:
				if (context.getGameTime().getTime() > 6000) {
					Object[] options = {"Yes, forfeit",
						"No, keep playing"};
					int n = JOptionPane.showOptionDialog(this,
							"Leaving now will cause you to lose this game?",
							"Really leave?",
							JOptionPane.YES_NO_OPTION,
							JOptionPane.QUESTION_MESSAGE,
							null, //do not use a custom Icon
							options, //the titles of buttons
							options[0]);
					if (n == JOptionPane.YES_OPTION) {
						sendLine(MessagePlayerForfeit.formatMessage(context.getGameTime().getTime(), playerGameId));
						return true;
					}
					return false;
				}
		}
		return true;
	}

	public void exitGame() {
		if (optionalForfeitGame()) {
			context.cleanContext();
			sendLine(MessageChannelJoin.formatMessage(0));
		}
	}

	public void setServerAddress(String address, int port) {
		serverAddress = address;
		serverPort = port;
		startClient();
	}

	public void startClient() {
		if (client == null && context != null) {
			status = "Connecting to server...";
			client = new NetworkClient(this);
			client.setPort(serverPort);
			client.setServer(serverAddress);
			client.connect();
			context.clientStarted();
		}
	}

	private void doJoin() {
		Object value = jListChannelList.getSelectedValue();
		if (value != null && value instanceof ChannelInfo) {
			ChannelInfo info = (ChannelInfo) value;
			sendLine(MessageChannelJoin.formatMessage(info.id));
		}
	}

	private void setNoConnection() {
		jTextField_send.setEnabled(false);
		jButton_send.setEnabled(false);
	}

	public void stop() {
		if (client != null) {
			client.stopClient();
		}
	}

	public void updatePlayerNames() {
		DefaultListModel m = (DefaultListModel) jListPlayerList.getModel();
		m.clear();
		for (int i = 0; i < players.size(); i++) {
			MPPlayerInfo info = players.get(i);
			m.addElement(info);
			ContextPlayer p = context.getPlayer(info.gameId);
			if (p != null) {
				p.setPlayerName(info.name);
				p.setUserId(info.userId);
			}
		}
	}

	public void updateChannelList() {
		if (!SwingUtilities.isEventDispatchThread()) {
			SwingUtilities.invokeLater(new Runnable() {

				@Override
				public void run() {
					updateChannelList();
				}
			});
		} else {

			DefaultListModel m = (DefaultListModel) jListChannelList.getModel();
			m.clear();
			for (Integer id : channelsById.keySet()) {
				ChannelInfo info = channelsById.get(id);
				if (id != 0) {
					m.addElement(info);
				}
			}
			setChannelTitle();
		}
	}

	public int getConnectedPlayerCount() {
		return players.size();
	}

	private void setChannelTitle() {
		ChannelInfo info = channelsById.get(channelId);
		if (info != null) {
			channelName = info.name;
		}
		TitledBorder b = (TitledBorder) jPanelChat.getBorder();
		b.setTitle("Chat: " + channelName);
		jPanelChat.repaint();
	}

	private void textReceived(int connection, String line) {
		if (keepFullLog) {
			fullLog.append(" <-- ");
			fullLog.append(line);
			fullLog.append("\n");
		}

		Message message = MessageFactory.GetMessage(line);

		switch (message.getType()) {
			case PlayerList:
				MessagePlayerList mpl = (MessagePlayerList) message;
				players = mpl.getPlayers();
				playersByUserId.clear();
				playersByGameId.clear();
				for (MPPlayerInfo info : players) {
					playersByUserId.put(info.userId, info);
					playersByGameId.put(info.gameId, info);
				}
				updatePlayerNames();
				break;

			case ChannelList:
				MessageChannelList mcl = (MessageChannelList) message;
				channelsById = mcl.getChannels();
				updateChannelList();
				break;

			case PlayerInChannel:
				context.getBlackBox().clear();
				context.getGameLoop().setRunning(false);
				MessagePlayerInChannel mic = (MessagePlayerInChannel) message;
				channelId = mic.getChannelId();

				playerGameId = mic.getPlayerId();
				context.setLocalPlayerId(playerGameId);
				System.out.println("PanelNetConnection::textReceived: Channel: " + channelId + " Player: " + playerGameId);
				setChannelTitle();
				jTextField_send.setEnabled(true);
				jButton_send.setEnabled(true);

				if (channelId == 0) {
					jPanelChannels.setVisible(true);
					jPanelInLobby.setVisible(true);
					jButtonExit.setVisible(false);
					context.setGameState(GameState.mpConnect);
					jButtonKick.setVisible(false);
					plr.setLongFormat(true);
				} else {
					ChannelInfo info = channelsById.get(channelId);
					channelName = info.name;
					jPanelInLobby.setVisible(false);
					jButtonExit.setVisible(true);
					plr.setLongFormat(true);
					switch (context.getGameState()) {
						case mpConnect:
						case mpSelecting:
						case mpClientSelecting:
							if (mic.isRunning()) {
								context.setGameState(GameState.mpJoinRunning);
								//context.getGameLoop().setTargetTick(mic.getLastTick());
								GameLoopImplementation.GliMpCatchup catchUpLoop = (GliMpCatchup) GameState.mpCatchup.gameLoop;
								catchUpLoop.setTargetTick(mic.getLastTick());
							} else {
								if (mic.getPlayerId() == 0) {
									context.setGameState(GameState.mpSelecting);
								} else {
									context.setGameState(GameState.mpClientSelecting);
								}
							}
							break;
					}
					if (mic.getPlayerId() == 0) {
						jButtonKick.setVisible(true);
					} else {
						jButtonKick.setVisible(false);
					}
				}
				break;

			case Say:
				MessageSay ms = (MessageSay) message;
				int speakerId = ms.getSenderId();
				MPPlayerInfo speaker = playersByUserId.get(speakerId);
				if (speaker != null) {
					int gameId = speaker.gameId;
					int relId = gameId % 6;
					String cls = "p" + relId;
					addOutputText("<span class='" + cls + "'>" + speaker.name + "</span>: " + HTMLEncode.encode(ms.getText()) + "<br>");
				} else {
					addOutputText(ms.getText());
				}
				break;

			case PlayerInfo:
				MessagePlayerInfo mpi = (MessagePlayerInfo) message;
				localPlayerInfo.updateFrom(mpi.getPlayerInfo(), true);
				status = "Connected to server and authenticated. Multiplayer available.";
				context.setAuthenticated(AuthStatus.success);
				doSendLater();
				break;

			case Error:
				MessageError me = (MessageError) message;
				switch (me.getErrorType()) {
					case AuthFailed:
						switch (context.getGameState()) {
							case titleScreen:
								status = "Connected to server but not authenticated.";
								context.setAuthenticated(AuthStatus.failed);
								context.showAlert("You are not logged in on Towerdefence.net:\n"
										+ "Only single player available.");
						}
						doSendLater();
						break;
					case ReplayLoadFailed:
						if (context.getGameState() == GameState.loadReplay) {
							status = "Failed to load replay!";
							context.setGameState(GameState.titleScreen);
						}
						break;

				}
				break;
			case Settings:
				MessageSettings mst = (MessageSettings) message;
				for (Entry<MessageSettings.settingKey, String> entry : mst.getSettings().entrySet()) {
					switch (entry.getKey()) {
						case ready:
							MPPlayerInfo player = playersByUserId.get(mst.getSenderId());
							if (player != null) {
								player.ready = Boolean.parseBoolean(entry.getValue());
							}
							break;
					}
				}
				context.setSettings(mst.getSettings());
				break;
			case Pong:
				break;
			case ReplayBasic:
				MessageReplayBasic mrb = (MessageReplayBasic) message;
				if (context.getGameState() == GameState.loadReplay) {
					context.loadReplay(mrb.getReplayLog());
				}
				break;
			case Unknown:
				System.out.println("PanelNetConnection::textReceived: Unknown message:\n" + message.getMessage());
				break;

			default:
				context.messageReceived(message);
				break;
		}
	}

	@Override
	public void sendLine(String line) {
		if (client == null && wasConnected) {
			startClient();
		}
		if (client != null) {
			client.sendLine(line);
			if (keepFullLog) {
				fullLog.append(" --> ");
				fullLog.append(line);
				fullLog.append("\n");
			}
		}
	}

	public void transmitSetting(MessageSettings.settingKey key, String value) {
		HashMap<MessageSettings.settingKey, String> table = new HashMap<MessageSettings.settingKey, String>();
		table.put(key, value);
		sendLine(MessageSettings.formatMessage(localPlayerInfo.userId, table));
	}

	public void transmitSetting(HashMap<MessageSettings.settingKey, String> table) {
		sendLine(MessageSettings.formatMessage(localPlayerInfo.userId, table));
	}

	public void sendUpdatedPlayerInfo() {
		sendLine(MessagePlayerInfo.formatMessage(localPlayerInfo));
	}

	private synchronized void addOutputText(String text) {
		htmlContent.insert(0, text);
		jTextPane_output.setText("<html><body>" + htmlContent + "</body></html>");
		jTextPane_output.setCaretPosition(0);
	}

	@Override
	public void connectionEstablished(NetworkConnection connection) {
		status = "Connected to server, authenticating...";
		//addOutputText("<-- " + connection.getId() + " New Connection!");
		final NetworkConnection newConnection = connection;
		connection.addLineListener(new LineListener() {

			@Override
			public void lineReceived(String line) {
				textReceived(newConnection.getId(), line);
			}

			@Override
			public void inputStopped() {
			}
		});
		context.newConnection(connection.getId());
		wasConnected = true;

		if (client != null) {
			sendLine(MessagePlayerAuth.formatMessage(localPlayerInfo.token));
		}
	}

	@Override
	public void connectionFailed(NetworkConnection connection, String reason) {
		status = "Connecting to server failed.";
		addOutputText("<div class='playerJoined'>Connection Failed because: " + reason + "</div>");
		context.setConnected(false);
		client.stopClient();
		client = null;
	}

	@Override
	public void connectionLost(NetworkConnection connection) {
		context.setConnected(false);
		context.setAuthenticated(AuthStatus.unknown);
		status = "Not connected to server.";
		client.stopClient();
		client = null;
		addOutputText("<div class='playerJoined'>Lost Connection!</div>");
		switch (context.getGameState()) {
			case mpPlaying:
			case mpWatching:
			case mpCatchup:
			case mpSelecting:
			case mpGameEnd:
				context.setGameState(GameState.titleScreen);
		}
	}

	public synchronized void loadReplay(boolean mp, int replayId) {
		String message;
		if (mp) {
			message = MessageFetch.formatMessage(replayId, FetchType.mp);
		} else {
			message = MessageFetch.formatMessage(replayId, FetchType.sp);
		}

		if (context.getAuthenticated() == AuthStatus.unknown) {
			sendLater = message;
		} else {
			sendLine(message);
		}
	}

	private synchronized void doSendLater() {
		if (sendLater != null) {
			sendLine(sendLater);
			sendLater = null;
		}
	}

	private void doSay() {
		String text = jTextField_send.getText();
		//connector.sendLine("say " + context.getLocalPlayerId() + " " + text);
		sendLine(MessageSay.formatMessage(localPlayerInfo.userId, text));
		addOutputText("<span class='p" + playerGameId + "'>" + localPlayerInfo.userName + "</span>: " + HTMLEncode.encode(text) + "<br>");
		jTextField_send.setText("");
	}

	public String getToken() {
		return localPlayerInfo.token;
	}

	public void setToken(String t) {
		localPlayerInfo.token = t;
	}

	public String getPlayerName() {
		return localPlayerInfo.userName;
	}

	private void kickPlayer() {
		MPPlayerInfo selected = (MPPlayerInfo) jListPlayerList.getSelectedValue();
		if (selected != null) {
			sendLine(MessageKickPlayer.formatMessage(selected.userId));
		}
	}

	@Override
	public void setVisible(boolean aFlag) {
		if (aFlag) {
			if (pingTimer == null) {
				pingTimer = new Timer("pingTimer", true);
			}
			if (pingTask == null) {
				pingTask = new TimerTask() {

					@Override
					public void run() {
						sendLine(MessagePing.formatMessage());
					}
				};
				pingTimer.schedule(pingTask, 120000, 120000);
			}
		} else {
			if (pingTask != null) {
				pingTask.cancel();
				pingTask = null;
			}
		}
		super.setVisible(aFlag);
	}

	public void showTextBar() {
		jTextField_send.setVisible(true);
		jTextField_send.requestFocusInWindow();
		jButton_send.setVisible(true);
	}

	public void hideTextBar() {
		if (!keepTextBar) {
			jTextField_send.setVisible(false);
			jButton_send.setVisible(false);
		}
	}

	/** This method is called from within the constructor to
	 * initialize the form.
	 * WARNING: Do NOT modify this code. The content of this method is
	 * always regenerated by the Form Editor.
	 */
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {
        java.awt.GridBagConstraints gridBagConstraints;

        jFrame1 = new javax.swing.JFrame();
        jScrollPane4 = new javax.swing.JScrollPane();
        jTextPaneFullLog = new javax.swing.JTextPane();
        jButton1 = new javax.swing.JButton();
        jButtonKick = new javax.swing.JButton();
        jPanelChat = new javax.swing.JPanel();
        jScrollPane1 = new javax.swing.JScrollPane();
        jTextPane_output = new javax.swing.JTextPane();
        jTextField_send = new javax.swing.JTextField();
        jButton_send = new javax.swing.JButton();
        jScrollPane2 = new javax.swing.JScrollPane();
        jListPlayerList = new javax.swing.JList();
        jPanelChannels = new javax.swing.JPanel();
        jPanelInLobby = new javax.swing.JPanel();
        jScrollPane3 = new javax.swing.JScrollPane();
        jListChannelList = new javax.swing.JList();
        jButtonJoin = new javax.swing.JButton();
        jButtonCreate = new javax.swing.JButton();
        jButtonExit = new javax.swing.JButton();

        jScrollPane4.setViewportView(jTextPaneFullLog);

        jFrame1.getContentPane().add(jScrollPane4, java.awt.BorderLayout.CENTER);

        jButton1.setText("refresh");
        jButton1.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton1ActionPerformed(evt);
            }
        });
        jFrame1.getContentPane().add(jButton1, java.awt.BorderLayout.SOUTH);

        setLayout(new java.awt.GridBagLayout());

        jButtonKick.setBackground(context.colors.getColorBackGround());
        jButtonKick.setForeground(context.colors.getColorForeGround());
        jButtonKick.setText("Kick");
        jButtonKick.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButtonKickActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 4;
        gridBagConstraints.gridy = 1;
        add(jButtonKick, gridBagConstraints);

        jPanelChat.setBackground(context.colors.getColorBackGround());
        jPanelChat.setBorder(javax.swing.BorderFactory.createTitledBorder(null, "Chat", javax.swing.border.TitledBorder.DEFAULT_JUSTIFICATION, javax.swing.border.TitledBorder.DEFAULT_POSITION, new java.awt.Font("Bitstream Vera Sans", 0, 13), context.colors.getColorForeGround())); // NOI18N
        jPanelChat.setForeground(context.colors.getColorForeGround());
        jPanelChat.setMaximumSize(new java.awt.Dimension(2147483647, 175));
        jPanelChat.setPreferredSize(new java.awt.Dimension(134, 175));
        jPanelChat.setLayout(new java.awt.GridBagLayout());

        jScrollPane1.setBackground(context.colors.getColorBackGround());
        jScrollPane1.setForeground(context.colors.getColorForeGround());
        jScrollPane1.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);

        jTextPane_output.setBackground(context.colors.getColorBackGround());
        jTextPane_output.setEditable(false);
        jTextPane_output.setForeground(context.colors.getColorForeGround());
        jScrollPane1.setViewportView(jTextPane_output);

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.gridwidth = 4;
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
        gridBagConstraints.weightx = 0.01;
        gridBagConstraints.weighty = 1.0E-4;
        jPanelChat.add(jScrollPane1, gridBagConstraints);

        jTextField_send.setBackground(context.colors.getColorBackGround());
        jTextField_send.setForeground(context.colors.getColorForeGround());
        jTextField_send.setText("Some text");
        jTextField_send.setCaretColor(context.colors.getColorForeGroundPale());
        jTextField_send.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jTextField_sendActionPerformed(evt);
            }
        });
        jTextField_send.addFocusListener(new java.awt.event.FocusAdapter() {
            public void focusLost(java.awt.event.FocusEvent evt) {
                jTextField_sendFocusLost(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.gridwidth = 3;
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
        gridBagConstraints.weightx = 0.01;
        jPanelChat.add(jTextField_send, gridBagConstraints);

        jButton_send.setBackground(context.colors.getColorBackGround());
        jButton_send.setForeground(context.colors.getColorForeGround());
        jButton_send.setText("Send");
        jButton_send.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton_sendActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 3;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHEAST;
        jPanelChat.add(jButton_send, gridBagConstraints);

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 3;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.gridheight = 2;
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTH;
        gridBagConstraints.weightx = 0.1;
        add(jPanelChat, gridBagConstraints);

        jScrollPane2.setBackground(context.colors.getColorBackGround());
        jScrollPane2.setBorder(javax.swing.BorderFactory.createTitledBorder(null, "Players", javax.swing.border.TitledBorder.DEFAULT_JUSTIFICATION, javax.swing.border.TitledBorder.DEFAULT_POSITION, new java.awt.Font("Bitstream Vera Sans", 0, 13), context.colors.getColorForeGround())); // NOI18N
        jScrollPane2.setForeground(context.colors.getColorForeGround());
        jScrollPane2.setMaximumSize(new java.awt.Dimension(150, 32767));
        jScrollPane2.setMinimumSize(new java.awt.Dimension(0, 0));
        jScrollPane2.setPreferredSize(new java.awt.Dimension(150, 128));

        jListPlayerList.setBackground(context.colors.getColorBackGround());
        jListPlayerList.setForeground(context.colors.getColorForeGround());
        jListPlayerList.setModel(new DefaultListModel());
        jListPlayerList.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
        jScrollPane2.setViewportView(jListPlayerList);

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 4;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.fill = java.awt.GridBagConstraints.VERTICAL;
        gridBagConstraints.weighty = 1.0E-7;
        add(jScrollPane2, gridBagConstraints);

        jPanelChannels.setBackground(context.colors.getColorBackGround());
        jPanelChannels.setForeground(context.colors.getColorForeGround());
        jPanelChannels.setLayout(new java.awt.GridBagLayout());

        jPanelInLobby.setBackground(context.colors.getColorBackGround());
        jPanelInLobby.setBorder(javax.swing.BorderFactory.createTitledBorder(null, "Games", javax.swing.border.TitledBorder.DEFAULT_JUSTIFICATION, javax.swing.border.TitledBorder.DEFAULT_POSITION, new java.awt.Font("Bitstream Vera Sans", 0, 13), context.colors.getColorForeGround())); // NOI18N
        jPanelInLobby.setForeground(context.colors.getColorForeGround());
        jPanelInLobby.setLayout(new java.awt.GridBagLayout());

        jScrollPane3.setBackground(context.colors.getColorBackGround());
        jScrollPane3.setForeground(context.colors.getColorForeGround());
        jScrollPane3.setMaximumSize(new java.awt.Dimension(100, 32767));
        jScrollPane3.setMinimumSize(new java.awt.Dimension(0, 0));
        jScrollPane3.setPreferredSize(new java.awt.Dimension(100, 157));

        jListChannelList.setBackground(context.colors.getColorBackGround());
        jListChannelList.setForeground(context.colors.getColorForeGround());
        jListChannelList.setModel(new DefaultListModel());
        jListChannelList.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
        jListChannelList.setCellRenderer(new ChannelListRenderer(context.colors));
        jListChannelList.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                jListChannelListMouseClicked(evt);
            }
        });
        jScrollPane3.setViewportView(jListChannelList);

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.gridwidth = 2;
        gridBagConstraints.gridheight = 3;
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
        gridBagConstraints.weightx = 0.01;
        gridBagConstraints.weighty = 0.01;
        jPanelInLobby.add(jScrollPane3, gridBagConstraints);

        jButtonJoin.setBackground(context.colors.getColorBackGround());
        jButtonJoin.setForeground(context.colors.getColorForeGround());
        jButtonJoin.setText("Join");
        jButtonJoin.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButtonJoinActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 3;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.SOUTHWEST;
        gridBagConstraints.insets = new java.awt.Insets(2, 0, 0, 2);
        jPanelInLobby.add(jButtonJoin, gridBagConstraints);

        jButtonCreate.setBackground(context.colors.getColorBackGround());
        jButtonCreate.setForeground(context.colors.getColorForeGround());
        jButtonCreate.setText("New");
        jButtonCreate.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButtonCreateActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 1;
        gridBagConstraints.gridy = 3;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.SOUTHEAST;
        gridBagConstraints.insets = new java.awt.Insets(2, 2, 0, 0);
        jPanelInLobby.add(jButtonCreate, gridBagConstraints);

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 2;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTH;
        gridBagConstraints.weightx = 0.01;
        gridBagConstraints.weighty = 0.01;
        jPanelChannels.add(jPanelInLobby, gridBagConstraints);

        jButtonExit.setBackground(context.colors.getColorBackGround());
        jButtonExit.setForeground(context.colors.getColorForeGround());
        jButtonExit.setText("Exit Game");
        jButtonExit.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButtonExitActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 1;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.SOUTH;
        gridBagConstraints.weighty = 0.01;
        jPanelChannels.add(jButtonExit, gridBagConstraints);

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridheight = 2;
        gridBagConstraints.fill = java.awt.GridBagConstraints.VERTICAL;
        add(jPanelChannels, gridBagConstraints);
    }// </editor-fold>//GEN-END:initComponents

	private void jButton_sendActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton_sendActionPerformed
		doSay();
		if (keepFullLog) {
			jTextPaneFullLog.setText(fullLog.toString());
			jFrame1.setVisible(true);
			jFrame1.pack();
		}
	}//GEN-LAST:event_jButton_sendActionPerformed

	private void jTextField_sendActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jTextField_sendActionPerformed
		doSay();
	}//GEN-LAST:event_jTextField_sendActionPerformed

	private void jButtonJoinActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonJoinActionPerformed
		doJoin();
	}//GEN-LAST:event_jButtonJoinActionPerformed

	private void jButtonCreateActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonCreateActionPerformed
		String s = JOptionPane.showInputDialog(
				"Please enter a name for your game",
				localPlayerInfo.userName + "'s Game");
		if ((s != null) && (s.length() > 0)) {
			sendLine(MessageChannelCreate.formatMessage(s));
		}
	}//GEN-LAST:event_jButtonCreateActionPerformed

	private void jButtonExitActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonExitActionPerformed
		exitGame();
	}//GEN-LAST:event_jButtonExitActionPerformed

	private void jListChannelListMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_jListChannelListMouseClicked
		if (evt.getClickCount() > 1) {
			doJoin();
		}
	}//GEN-LAST:event_jListChannelListMouseClicked

	private void jButtonKickActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonKickActionPerformed
		kickPlayer();
	}//GEN-LAST:event_jButtonKickActionPerformed

	private void jTextField_sendFocusLost(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_jTextField_sendFocusLost
		hideTextBar();
	}//GEN-LAST:event_jTextField_sendFocusLost

	private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton1ActionPerformed
		jTextPaneFullLog.setText(fullLog.toString());
	}//GEN-LAST:event_jButton1ActionPerformed
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton jButton1;
    private javax.swing.JButton jButtonCreate;
    private javax.swing.JButton jButtonExit;
    private javax.swing.JButton jButtonJoin;
    private javax.swing.JButton jButtonKick;
    private javax.swing.JButton jButton_send;
    private javax.swing.JFrame jFrame1;
    private javax.swing.JList jListChannelList;
    private javax.swing.JList jListPlayerList;
    private javax.swing.JPanel jPanelChannels;
    private javax.swing.JPanel jPanelChat;
    private javax.swing.JPanel jPanelInLobby;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JScrollPane jScrollPane2;
    private javax.swing.JScrollPane jScrollPane3;
    private javax.swing.JScrollPane jScrollPane4;
    private javax.swing.JTextField jTextField_send;
    private javax.swing.JTextPane jTextPaneFullLog;
    private javax.swing.JTextPane jTextPane_output;
    // End of variables declaration//GEN-END:variables

	/**
	 * @return the status
	 */
	public String getStatus() {
		return status;
	}

	/**
	 * @return the keepTextBar
	 */
	public boolean isKeepTextBar() {
		return keepTextBar;
	}

	/**
	 * @param keepTextBar the keepTextBar to set
	 */
	public void setKeepTextBar(boolean ktb) {
		if (keepTextBar != ktb) {
			keepTextBar = ktb;
			jTextField_send.setVisible(ktb);
			jButton_send.setVisible(ktb);
		}
	}

	/**
	 * @return the localPlayerInfo
	 * After making changes to the local player info,
	 * @see sendUpdatedPlayerInfo() must be called to send the changes to the
	 * server.
	 */
	public PlayerInfo getLocalPlayerInfo() {
		return localPlayerInfo;
	}
}
